/**
 ******************************************************************************
 * @file           : bsp_rs485.c
 * @brief          : RS485 Driver Implementation (STM32F1xx) Driver Implementation
 ******************************************************************************
 * @attention
 *
 * RS485半双工通信驱动程序实现文件
 * 支持中断接收和阻塞发送
 * 自动控制收发模式切换
 * 提供完整的错误处理机制
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/RS485/bsp_rs485.h"
#include "./BSP/RS485/bsp_rs485_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static UART_HandleTypeDef sg_rs485_uart_handle;                 /*!< RS485 UART句柄 */
static uint8_t sg_rs485_rx_buffer[RS485_RX_BUF_SIZE];           /*!< 接收缓冲区 */
static volatile uint16_t sg_rs485_rx_count = 0;                 /*!< 接收数据计数器 */
static volatile RS485_State_e sg_rs485_state = RS485_STATE_IDLE;/*!< RS485当前状态 */
static volatile uint8_t sg_rs485_initialized = 0;               /*!< 初始化标志 */

/* Private function prototypes -----------------------------------------------*/
static void rs485_gpio_init(void);
static void rs485_uart_init(uint32_t baudrate);
static void rs485_switch_to_rx(void);
static void rs485_switch_to_tx(void);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       RS485 GPIO引脚初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置TX/RX/RE引脚，包括重映射配置
 */
static void rs485_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    /* 使能AFIO时钟（用于引脚重映射） */
    __HAL_RCC_AFIO_CLK_ENABLE();
    
    /* 使能GPIO时钟 */
    RS485_RE_GPIO_CLK_ENABLE();
    RS485_TX_GPIO_CLK_ENABLE();
    RS485_RX_GPIO_CLK_ENABLE();
    
    /* 配置引脚重映射（如果需要） */
    RS485_GPIO_REMAP_CONFIG();
    
    /* 配置TX引脚 - 复用推挽输出 */
    gpio_init_struct.Pin = RS485_TX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_init_struct);
    
    /* 配置RX引脚 - 复用输入 */
    gpio_init_struct.Pin = RS485_RX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;
    HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_init_struct);
    
    /* 配置RE引脚 - 推挽输出 */
    gpio_init_struct.Pin = RS485_RE_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_RE_GPIO_PORT, &gpio_init_struct);
}

/**
 * @brief       RS485 UART初始化
 *
 * @param[in]   baudrate 波特率
 *
 * @retval      无
 *
 * @note        配置UART参数并使能接收中断
 */
static void rs485_uart_init(uint32_t baudrate)
{
    /* 使能UART时钟 */
    RS485_UARTx_CLK_ENABLE();
    
    /* 配置UART参数 */
    sg_rs485_uart_handle.Instance = RS485_UARTx;
    sg_rs485_uart_handle.Init.BaudRate = baudrate;
    sg_rs485_uart_handle.Init.WordLength = UART_WORDLENGTH_8B;
    sg_rs485_uart_handle.Init.StopBits = UART_STOPBITS_1;
    sg_rs485_uart_handle.Init.Parity = UART_PARITY_NONE;
    sg_rs485_uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    sg_rs485_uart_handle.Init.Mode = UART_MODE_TX_RX;
    
    if (HAL_UART_Init(&sg_rs485_uart_handle) != HAL_OK)
    {
        log_e("UART初始化失败");
        return;
    }
    
    /* 配置并使能接收中断 */
    __HAL_UART_ENABLE_IT(&sg_rs485_uart_handle, UART_IT_RXNE);
    HAL_NVIC_SetPriority(RS485_UARTx_IRQn, 3, 3);
    HAL_NVIC_EnableIRQ(RS485_UARTx_IRQn);
}

/**
 * @brief       切换到接收模式
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        设置RE=0进入接收模式
 */
static void rs485_switch_to_rx(void)
{
    RS485_RX_MODE();
    sg_rs485_state = RS485_STATE_RX;
}

/**
 * @brief       切换到发送模式
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        设置RE=1进入发送模式
 */
static void rs485_switch_to_tx(void)
{
    RS485_TX_MODE();
    sg_rs485_state = RS485_STATE_TX;
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       RS485初始化
 *
 * @param[in]   baudrate 波特率(如9600, 115200等)
 *
 * @retval      无
 *
 * @note        初始化GPIO、UART和中断，默认进入接收模式
 * @note        初始化成功后自动清空接收缓冲区
 */
void rs485_init(uint32_t baudrate)
{
    /* 参数检查 */
    if (baudrate == 0)
    {
        log_w("波特率参数无效，使用默认值: %d", RS485_DEFAULT_BAUDRATE);
        baudrate = RS485_DEFAULT_BAUDRATE;
    }
    
    /* 初始化GPIO */
    rs485_gpio_init();
    
    /* 初始化UART */
    rs485_uart_init(baudrate);
    
    /* 清空接收缓冲区 */
    sg_rs485_rx_count = 0;
    
    /* 切换到接收模式 */
    rs485_switch_to_rx();
    
    /* 标记已初始化 */
    sg_rs485_initialized = 1;
    
    log_i("RS485初始化完成 - 波特率: %lu", baudrate);
}

/**
 * @brief       RS485反初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        关闭UART和中断，释放资源
 */
void rs485_deinit(void)
{
    if (!sg_rs485_initialized)
    {
        return;
    }
    
    /* 禁用UART中断 */
    HAL_NVIC_DisableIRQ(RS485_UARTx_IRQn);
    __HAL_UART_DISABLE_IT(&sg_rs485_uart_handle, UART_IT_RXNE);
    
    /* 反初始化UART */
    HAL_UART_DeInit(&sg_rs485_uart_handle);
    
    /* 清除标志 */
    sg_rs485_initialized = 0;
    sg_rs485_state = RS485_STATE_IDLE;
    
    log_i("RS485已反初始化");
}

/**
 * @brief       RS485发送数据
 *
 * @param[in]   data 发送数据指针
 * @param[in]   len  发送数据长度(字节)
 *
 * @retval      RS485_OK         发送成功
 * @retval      RS485_ERROR_PARAM 参数错误
 * @retval      RS485_ERROR_TIMEOUT 发送超时
 *
 * @note        自动切换到发送模式，发送完成后切换回接收模式
 * @note        发送过程中会清空接收缓冲区
 */
RS485_Error_e rs485_send(const uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef status;
    
    /* 参数检查 */
    if (data == NULL || len == 0)
    {
        log_w("发送参数错误: data=%p, len=%d", data, len);
        return RS485_ERROR_PARAM;
    }
    
    if (!sg_rs485_initialized)
    {
        log_e("RS485未初始化");
        return RS485_ERROR_PARAM;
    }
    
    /* 切换到发送模式 */
    rs485_switch_to_tx();
    
    /* 清空接收缓冲区 */
    sg_rs485_rx_count = 0;
    
    /* 发送数据 */
    status = HAL_UART_Transmit(&sg_rs485_uart_handle, (uint8_t*)data, len, RS485_TX_TIMEOUT);
    
    /* 切换回接收模式 */
    rs485_switch_to_rx();
    
    if (status != HAL_OK)
    {
        log_e("发送失败: status=%d, len=%d", status, len);
        return RS485_ERROR_TIMEOUT;
    }
    
    log_d("发送成功: %d字节", len);
    return RS485_OK;
}

/**
 * @brief       RS485接收数据
 *
 * @param[out]  data 接收数据存储指针
 * @param[out]  len  返回接收到的数据长度
 *
 * @retval      RS485_OK         接收成功
 * @retval      RS485_ERROR_PARAM 参数错误
 *
 * @note        从接收缓冲区复制数据，非阻塞
 * @note        接收完成后自动清空接收缓冲区
 */
RS485_Error_e rs485_receive(uint8_t *data, uint16_t *len)
{
    uint16_t rx_count;
    
    /* 参数检查 */
    if (data == NULL || len == NULL)
    {
        log_w("接收参数错误: data=%p, len=%p", data, len);
        return RS485_ERROR_PARAM;
    }
    
    if (!sg_rs485_initialized)
    {
        log_e("RS485未初始化");
        *len = 0;
        return RS485_ERROR_PARAM;
    }
    
    /* 读取接收计数 */
    rx_count = sg_rs485_rx_count;
    *len = 0;
    
    /* 检查是否有数据 */
    if (rx_count == 0)
    {
        return RS485_OK;
    }
    
    /* 等待一段时间，判断接收是否完成 */
    RS485_DELAY_MS(10);
    
    /* 检查接收是否完成(10ms内计数器未变化) */
    if (rx_count == sg_rs485_rx_count)
    {
        /* 复制数据 */
        for (uint16_t i = 0; i < rx_count; i++)
        {
            data[i] = sg_rs485_rx_buffer[i];
        }
        
        *len = rx_count;
        
        /* 清空接收缓冲区 */
        sg_rs485_rx_count = 0;
        
        log_d("接收成功: %d字节", *len);
    }
    
    return RS485_OK;
}

/**
 * @brief       获取接收数据量
 *
 * @param       无
 *
 * @retval      当前接收缓冲区中的数据量(字节)
 *
 * @note        非阻塞，立即返回
 */
uint16_t rs485_get_rx_count(void)
{
    return sg_rs485_rx_count;
}

/**
 * @brief       清空接收缓冲区
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        丢弃所有未读取的数据
 */
void rs485_flush_rx(void)
{
    sg_rs485_rx_count = 0;
    log_d("接收缓冲区已清空");
}

/**
 * @brief       获取RS485当前状态
 *
 * @param       无
 *
 * @retval      RS485_State_e 当前状态
 *
 * @note        用于状态监控和调试
 */
RS485_State_e rs485_get_state(void)
{
    return sg_rs485_state;
}

/**
 * @brief       检查是否有接收数据
 *
 * @param       无
 *
 * @retval      1 有数据
 * @retval      0 无数据
 *
 * @note        快速检查接收缓冲区状态
 */
uint8_t rs485_is_rx_ready(void)
{
    return (sg_rs485_rx_count > 0) ? 1 : 0;
}

/**
 * @brief       打印RS485当前状态（用于调试）
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        显示波特率、状态、接收缓冲区等信息
 */
void rs485_print_status(void)
{
    const char *state_str[] = {"IDLE", "TX", "RX", "ERROR"};
    
    log_i("RS485当前状态:");
    log_i("  初始化状态: %s", sg_rs485_initialized ? "已初始化" : "未初始化");
    log_i("  波特率: %lu", sg_rs485_uart_handle.Init.BaudRate);
    log_i("  当前状态: %s", state_str[sg_rs485_state]);
    log_i("  接收缓冲区大小: %d 字节", RS485_RX_BUF_SIZE);
    log_i("  当前接收数据量: %d 字节", sg_rs485_rx_count);
    
    if (sg_rs485_rx_count > 0)
    {
        log_i("  接收缓冲区内容 (前16字节):");
        for (uint16_t i = 0; i < sg_rs485_rx_count && i < 16; i++)
        {
            log_i("    [%d] = 0x%02X", i, sg_rs485_rx_buffer[i]);
        }
    }
}

/**
 * @brief       RS485 UART中断处理函数
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        在中断中将接收数据存入缓冲区
 * @note        缓冲区满时丢弃新数据并记录错误日志
 * @note        中断函数名根据RS485_USART_SELECT_NUM自动生成
 */
void RS485_USARTx_IRQHandler(void)
{
    uint8_t data;
    
    /* 检查接收中断 */
    if (__HAL_UART_GET_FLAG(&sg_rs485_uart_handle, UART_FLAG_RXNE) != RESET)
    {
        /* 读取数据 */
        if (HAL_UART_Receive(&sg_rs485_uart_handle, &data, 1, 1) == HAL_OK)
        {
            /* 检查缓冲区是否已满 */
            if (sg_rs485_rx_count < RS485_RX_BUF_SIZE)
            {
                sg_rs485_rx_buffer[sg_rs485_rx_count++] = data;
            }
            else
            {
                /* 缓冲区溢出 */
                log_w("接收缓冲区溢出，丢弃数据");
                sg_rs485_state = RS485_STATE_ERROR;
            }
        }
    }
}
